
// GitHub
// Cyndi:petra n7down$ git push -u origin master

#include <ctime>

#include "OpenGL.h"
#include "Camera.h"
#include "Mouse.h"
#include "Displacement.h"
#include "SubdivisionSurface.h"
#include "Light.h"

// #include "MaterialManager.h"
#include "Obj.h"
#include "Tga.h"

#include <cmath>

using namespace std;
using namespace Velyn;

//-------------------------------------------------------------------------------
// Prototypes
//-------------------------------------------------------------------------------

void display();
void keyboardPress(unsigned char key, int x, int y);
void keyboardRelease(unsigned char key, int x, int y);
void reshape(int w, int h);
void animate(int extra);
void initialize();
void mouseButtonPress(int button, int state, int x, int y);
void mouseMotion(int x, int y);

//-------------------------------------------------------------------------------
// Globals
//-------------------------------------------------------------------------------

Camera camera;
Mouse mouse;

float dist, d;

Vector3 p0, p1, p2, u, v, n;

float value;

Vector3 planeNormal, point1, point;
Vector4 plane, point2, newPoint;

float generateRandomFloatValue(float lowValue, float highValue) {
    return ((highValue - lowValue) * ((float)rand() / RAND_MAX)) + lowValue;
}

// !!!: use this:
// http://www.lighthouse3d.com/tutorials/maths/plane/
void movePoint() {
    
    point.setValue(value, value, value);

    dist = n.dot(point) + d;
    
    cout << "D: " << d << endl;
    
    cout << "Point: ";
    point.print();
    
    cout << endl;
    cout << "Distance: " << dist << endl;
}

void projectPoint() {
    point = point - (dist/2) * n;
    
    dist = n.dot(point) + d;
    
    value = point.x;
    
    point.setValue(value, value, value);
    
    cout << "Point: ";
    point.print();
}

//-------------------------------------------------------------------------------
// Display
//-------------------------------------------------------------------------------

void display() {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	camera.enable();
    
    mouse.rotateObject();
    
    // show only wireframes
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    
    // create compass
    glBegin(GL_LINES);
    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glVertex3f(1.0f, 0.0f, 0.0f);
    glEnd();
    
    glBegin(GL_LINES);
    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glVertex3f(0.0f, 1.0f, 0.0f);
    glEnd();
    
    glBegin(GL_LINES);
    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glVertex3f(0.0f, 0.0f, 1.0f);
    glEnd();
    
    // render plane normal
    glBegin(GL_LINES);
    glColor3f(1.0f, 1.0f, 0.0f);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glVertex3fv(n.getValue());
    glEnd();
    
    // render the plane
    glBegin(GL_TRIANGLES);
    glColor3f(0.0f, 1.0f, 1.0f);
    glVertex3f(n.x, 0.0f, 0.0f);
    glVertex3f(0.0f, n.y, 0.0f);
    glVertex3f(0.0f, 0.0f, n.z);
    glEnd();
    
    // render the point
    glPointSize(3.0f);
    glBegin(GL_POINTS);
    glColor3f(1.0f, 1.0f, 1.0f);
    glVertex3fv(point.getValue());
    glEnd();
    
    glutSwapBuffers();
}

//-------------------------------------------------------------------------------
// Keyboard Press
//-------------------------------------------------------------------------------

void keyboardPress(unsigned char key, int x, int y) {
	Displacement displacement;
	
	switch(key) {
		case 27: {
			exit(0);
		} break;
			
		case '`': {
			// console stuff..
		} break;
			
		case 'a': {
            // point.setValue(1.0f, 1.0f, 1.0f);
            // point1.setValue(1.0f, 1.0f, 1.0f, 1.0f);
            // point.setValue(1.0f, 1.0f, 1.0f);
            value += 0.01;
            movePoint();
        } break;
			
		case 's': {
            // point.setValue(1.0f, 1.0f, 1.0f);
            // point1.setValue(1.0f, 1.0f, 1.0f, 1.0f);
            // point.setValue(1.0f, 1.0f, 1.0f);
            value -= 0.01;
            movePoint();
		} break;
            
        case 'z': {
            projectPoint();
        } break;
            
		default: {
			
		} break;
	}
}

//-------------------------------------------------------------------------------
// Keyboard Release
//-------------------------------------------------------------------------------

void keyboardRelease(unsigned char key, int x, int y) {}

//-------------------------------------------------------------------------------
// Reshape
//-------------------------------------------------------------------------------

void reshape(int w, int h) {
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0, 1.6, 1.0, 200.0);
}

//-------------------------------------------------------------------------------
// Timer
//-------------------------------------------------------------------------------

void animate(int extra) {
	// camera.animate();
	
	glutPostRedisplay();
	glutTimerFunc(40, animate, 0);
} 

//-------------------------------------------------------------------------------
// Initialize
//-------------------------------------------------------------------------------

void initialize() {
    
    p0.setValue(1.0f, 0.0f, 0.0f);
    p1.setValue(0.0f, 1.0f, 0.0f);
    p2.setValue(0.0f, 0.0f, 1.0f);
    
    u = p1 - p0;
    v = p2 - p0;
    
    n = u.cross(v);
    
    n.normalize();
    
    d = -(n.dot(p0));
    
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glShadeModel(GL_SMOOTH);
    
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_NORMALIZE);
    
	glMatrixMode(GL_PROJECTION);		
	glLoadIdentity();
	gluPerspective(45.0, 1.6, 1.0, 200.0);
}

//-------------------------------------------------------------------------------
// Mouse Press
//-------------------------------------------------------------------------------

void mouseButtonPress(int button, int state, int x, int y) {
    mouse.pressEvent(button, state, x, y);
}

//-------------------------------------------------------------------------------
// Mouse Motion
//-------------------------------------------------------------------------------

void mouseMotion(int x, int y) {
    mouse.motionEvent(x, y);
}

//-------------------------------------------------------------------------------
// Main
//-------------------------------------------------------------------------------

int main(int argc, char** argv) {
	
    glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
	glutInitWindowSize(800, 500);
	glutInitWindowPosition(100, 100);
	glutCreateWindow("Petra");
	initialize();
	
	glutKeyboardFunc(keyboardPress);
	glutKeyboardUpFunc(keyboardRelease);
	
	glutMouseFunc(mouseButtonPress);
	glutMotionFunc(mouseMotion);
	
	glutTimerFunc(25, animate, 0);
	glutDisplayFunc(display);
	
	glutReshapeFunc(reshape);
    
	glutMainLoop();
}

